package indicators

import (
	"math"

	"gitee.com/lyuanbo/stock-plus/pkg/stock/types"
)

// CCI 顺势指标（Commodity Channel Index）指标通常用于衡量股票价格是否超买或超卖。
// TYP:=(HIGH+LOW+CLOSE)/3;
// CCI:(TYP-MA(TYP,N))/(0.015*AVEDEV(TYP,N));
// TYP比较容易理解，（最高价+最低价+收盘价）÷3
// MA(TYP,N) 也比较简单，就是N天的TYP的平均值
// AVEDEV(TYP,N) 比较难理解，是对TYP进行绝对平均偏差的计算。
// 也就是说N天的TYP减去MA(TYP,N)的绝对值的和的平均值。
// 表达式：
// MA = MA(TYP,N)
// AVEDEV(TYP,N) =( | 第N天的TYP - MA |   +  | 第N-1天的TYP - MA | + ...... + | 第1天的TYP - MA | ) ÷ N
// CCI = （TYP－MA）÷ AVEDEV(TYP,N)   ÷0.015
func CCI(klines []*types.Kline, period int) {
	if len(klines) < period {
		return
	}

	for i := period - 1; i < len(klines); i++ {
		// 计算Typical Price
		f1, _ := klines[i].KlineInfo.High.Add(klines[i].KlineInfo.Low).Add(klines[i].KlineInfo.Close).Float64()
		tp := (f1) / 3.0

		// 计算SMA（简单移动平均）
		smaSum := 0.0
		for j := i - (period - 1); j <= i; j++ {
			// 计算周期内的典型价格之和
			f2, _ := klines[j].KlineInfo.High.Add(klines[j].KlineInfo.Low).Add(klines[j].KlineInfo.Close).Float64()
			smaSum += (f2) / 3.0
		}
		// 计算SMA
		sma := smaSum / float64(period)

		// 计算MAD（平均偏差）
		mdSum := 0.0
		for j := i - (period - 1); j <= i; j++ {
			// 计算周期内的典型价格与SMA之间的偏差之和
			f3, _ := klines[j].KlineInfo.High.Add(klines[j].KlineInfo.Low).Add(klines[j].KlineInfo.Close).Float64()
			mdSum += math.Abs(((f3) / 3.0) - sma)
		}
		// 计算平均偏差
		mad := mdSum / float64(period)

		// 计算CCI（商品通道指数）
		cci := (tp - sma) / (0.015 * mad) // 注意：修正CCI的除数为0.015

		// 四舍五入
		klines[i].CCI = math.Round(cci*100.0) / 100.0
	}
}
